/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ADT;

import Interfaces.Bounded3DimStack;
import Interfaces.StowageLocation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 *
 * @author markusbaisch
 */
public class Bounded3DimStackImpl<E> implements Bounded3DimStack<E> {
    StowageLocation loc;
    List<List<List<E>>> stack;

    // Konstruktor
    private Bounded3DimStackImpl(StowageLocation loc) {
        this.loc = loc;
        // Stack init
        stack = new ArrayList( loc.bay() );
        for( int bay_i=0; bay_i < loc.bay(); ++bay_i )
        {
            stack.add(bay_i, new ArrayList( loc.row() ));
            for( int row_i=0; row_i < loc.row(); ++row_i )
            {
                stack.get(bay_i).add( row_i, new ArrayList( loc.tier()));
            }
        }
    }

    static Bounded3DimStack valueOf(StowageLocation loc) {
        return new Bounded3DimStackImpl( loc );
    }
    
    @Override
    public void load(int bayNo, int rowNo, E elem) {
        if( tierIsFull(bayNo, rowNo) ) throw new IllegalArgumentException("Tier is full");
        stack.get( bayNo ).get( rowNo ).add( elem );
    }

    @Override
    public void load(E elem) {
        if(isFull()) throw new IllegalArgumentException("Stack is full");
        for(int bay_i = 0; bay_i < loc.bay(); ++bay_i)
        {
            for(int row_i = 0; row_i < loc.row(); ++row_i)
            {
                if(!(tierIsFull(bay_i,row_i)))
                {
                    load(bay_i,row_i,elem);
                    // abbruch
                    return;
                }
            }
        }
    }

    @Override
    public void loadAll(Collection<? extends E> coll) {
        if(isFull()) throw new IllegalArgumentException("Stack is full");
        if(coll.size() > ((loc.row() * loc.bay() * loc.tier()) - getAll().size()) ) throw new IllegalArgumentException("too many items");
        for(E elem : coll)
            load(elem);
    }

    @Override
    public boolean isEmpty() {
        return getAll().size() == 0;
    }

    @Override
    public boolean isFull() {
        return getAll().size() >= (loc.row() * loc.bay() * loc.tier() );
    }

    @Override
    public boolean tierIsEmpty(int bayNo, int rowNo) {
        if(loc.bay() >= bayNo && loc.row() >= rowNo)
            return stack.get(bayNo).get(rowNo).isEmpty();
        return false;
    }

    @Override
    public boolean tierIsFull(int bayNo, int rowNo) {
        if(loc.bay() >= bayNo && loc.row() >= rowNo)
            return stack.get(bayNo).get(rowNo).size() == loc.tier();
        return true;
    }

    @Override
    public boolean contains(Object elem) {
        return getAll().contains( elem );
    }

    @Override
    public boolean containsAll(Collection<?> coll) {
        return getAll().containsAll(coll);
    }

    @Override
    public E get(StowageLocation loc) {
        if(loc.row() > this.loc.row() || loc.bay() > this.loc.bay() || loc.tier() > this.loc.tier()) throw new IllegalArgumentException("bad Location");
        return stack.get(loc.bay()).get(loc.row()).get(loc.tier());
    }

    @Override
    public Set<E> getAll() {
        HashSet set = new HashSet();
        for(int bay_i = 0; bay_i < loc.bay(); ++bay_i)
        {
            for(int row_i = 0; row_i < loc.row(); ++row_i)
            {
                set.addAll( stack.get(bay_i).get(row_i) );
            }
        }
        return set;
    }

    @Override
    public StowageLocation locationOf(E elem) {
        for(int bay_i = 0; bay_i < loc.bay(); ++bay_i)
        {
            for(int row_i = 0; row_i < loc.row(); ++row_i)
            {
                for(int tier_i = 0; tier_i < stack.get(bay_i).get(row_i).size(); ++tier_i )
                {
                    if(stack.get(bay_i).get(row_i).get(tier_i) == elem)
                        return Entities.stowageLocation(bay_i, row_i, tier_i);
                }
            }
        }
        // nicht gefunden
        return Entities.nullLocation();
    }

}
